package myJs.genome

import myJs.Implicits._
import myJs.myPkg.jquery._
import myJs.myPkg.{ColumnOptions, Select2Options, TableOptions, layer}
import myJs.tool.Pojo.FilterContentData
import myJs.tool.Tool
import org.scalajs.dom.{Element, document}
import org.scalajs.dom.ext.Ajax
import scalatags.Text.all
import scalatags.Text.all._

import scala.collection.immutable.SeqMap
import scala.concurrent.ExecutionContext.Implicits.global
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import scala.scalajs.js.Dynamic.{global => g}
import scala.scalajs.js.JSON

/**
 * Created by yz on 13/11/2020
 */
@JSExportTopLevel("Browse")
object Browse {

  val tableId = "table"
  val map = SeqMap("id" -> "ID", "geneName" -> "Symbol", "description" -> "Description", "locus" -> "Locus",
    "strand" -> "Strand", "qeuryLength" -> "Query_length", "nrTophitName" -> "NR_tophit_name",
    "nrTophitDescrip" -> "NR_tophit_descrip", "nrTopSimil" -> "NR_top_%-Simil", "swissTophitName" -> "Swiss_tophit_name",
    "swissprotTophitDescrip" -> "Swissprot_tophit_descrip", "swissprotTopSimil" -> "Swissprot_top_%-Simil",
    "gos" -> "GOs", "cog" -> "COG/KOG", "function" -> "Function", "ko" -> "KO/Gene_ID",
    "keggGeneName" -> "KEGG_GENE_NAME")
  val parentId = ""
  var loadingIndex: Int = _

  @JSExport("init")
  def init = {
    initTable
    registerEvent
  }

  def registerEvent = {
    tableFilterEvent
    $(document.body).on("click", s".myShow", "", (y: Element) => {
      val text = $(y).text()
      text match {
        case "» show all" =>
          $(y).parents(".eachGo").find(".hide").removeClass("hide").
            addClass("show")
          $(y).text("« hide")
        case "« hide" =>
          $(y).parents(".eachGo").find(".show").removeClass("show").
            addClass("hide")
          $(y).text("» show all")
      }
    })
  }

  def tableFilterEvent = {
    Tool.clickHide

    $(document.body).on("click", s".myOperate", "", (y: Element) => {
      Tool.filterContentShow(y, parentId)
    })
    $(document.body).on("click", s".mySortLi", "", (y: Element) => {
      Tool.execSort(y, parentId, () => {
        refreshTable()
      })
    })
    $(document.body).on("click", s".myConfirm", "", (y: Element) => {
      Tool.confirmFilter(y, parentId, () => {
        refreshTable()
      })
    })
    $(document.body).on("click", s".myHide", "", (y: Element) => {
      Tool.hideFilterContent(y)
    })
    $(document.body).on("click", s".myRemove", "", (y: Element) => {
      Tool.removeCondition(y, parentId, () => {
        refreshTable()
      })
    })
    $(document.body).on("click", s".myRemoveSort", "", (y: Element) => {
      Tool.removeSort(y, parentId, () => {
        refreshTable()
      })
    })
  }

  def getParentJq = {
    Tool.getParentJq(parentId)
  }

  def refreshTable(f: () => js.Any = () => ()) = {
    getParentJq.find(s"#${tableId}").bootstrapTable("refresh")
    f()
  }

  def tbFmt(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[js.Any]) => columnName match {
    case "id" =>
      val url = g.jsRoutes.controllers.AnnoController.getDetailInfo().url
      val hf = s"${url}?geneId=${v}"
      a(
        target := "_blank",
        href := hf
      )(v.toString).render
    case "gos" =>
      val vs = v.toString.split(";")
      val allV = vs.zipWithIndex.map { case (v, curI) =>
        val cls = if (curI < 3) {
          "alwaysShow"
        } else "hide"
        span(`class` := s"${cls}", all.raw(v), br)
      }.mkString
      val actionA = if (vs.size > 3) {
        a(href := "javascript:void(0)", `class` := "myShow", "» show all")
      } else span()
      span(`class` := "eachGo", all.raw(allV),
        actionA
      )
    case _ => v
  }

  def expStyle(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[Any]) => columnName match {
    case _ => v
  }

  def refreshSelect2(keys: List[String]) = {
    val url = g.jsRoutes.controllers.AnnoController.getSelect2Values().url.toString
    val data = js.Dictionary(
      "keys" -> keys.toJSArray
    )
    Ajax.post(url = s"${url}", data = JSON.stringify(data), headers = Map("Content-Type" -> "application/json")).map { xhr =>
      val rs = xhr.responseText.toJDJAn
      rs.foreach { case (k, v) =>
        val inputName = k
        val data = v.toJArS
        val array = data.filter(_.nonBlank).map { v =>
          js.Dictionary("text" -> v, "id" -> v)
        }
        val options = Select2Options(data=array.toJSArray,multiple=true,placeholder="click to choose")
        Tool.getInputByName(inputName).mySelect2(options)
      }
    }
  }

  def initFilterContent(tabId: String = "", map: SeqMap[String, String]) = {
    val textSortDatas = List("id", "description", "locus", "geneName", "nrTophitName", "nrTophitDescrip", "nrTopSimil",
      "swissTophitName", "swissprotTophitDescrip", "swissprotTopSimil", "gos", "cog", "function", "ko",
      "keggGeneName").map { fieldName =>
      FilterContentData(fieldName, map(fieldName))
    }
    val select2Keys = List("strand")
    val select2SortDatas = select2Keys.map { x =>
      FilterContentData(x, map(x), List.empty)
    }

    val rangeSortDatas = List("qeuryLength").map { x =>
      FilterContentData(x, map(x))
    }

    Tool.initFilterContent(textSortDatas = textSortDatas, select2SortDatas = select2SortDatas,
      rangeSortDatas = rangeSortDatas, parentId = s"${tabId}")
    refreshSelect2(select2Keys)
    textSortDatas ::: select2SortDatas ::: rangeSortDatas
  }

  def pageChange: js.Function = (number: Int, size: Int) => {
    showLoading
  }

  def showLoading = {
    loadingIndex = layer.load(0, Tool.layerOptions.copy(shade=List("0.1", "#fff")))
  }

  def onLoadSuccess: js.Function = { () =>
    layer.close(loadingIndex)
  }

  def onRefreshF: js.Function = (params: js.Any) => {
    showLoading
  }

  def initTable = {
    val allDatas = initFilterContent(map = map)
    val columnNames = map.keyList
    val columns = columnNames.map { columnName =>
      val title = map.getOrElse(columnName, columnName)
      val fmt = tbFmt(columnName)
      val style = expStyle(columnName)
      val basicOptions = ColumnOptions.field(columnName).title(title).titleTooltip(title).sortable(true).
        formatter(fmt).cellStyle(style)
      columnName match {
        case x if allDatas.map(_.fieldName).contains(x) => basicOptions.
          sortable(false).operateable(true)
        case _ => basicOptions
      }
    }
    val options = TableOptions.columns(columns.toJSArray).searchOnButton(false).filterControl(false).search(true).
      method("post").
      sidePagination("server").ajax(ajaxRequest).onPageChange(pageChange).onLoadSuccess(onLoadSuccess).
      onRefresh(onRefreshF)
    $(s"#${tableId}").bootstrapTable(options)
    Tool.refreshCheckboxView(map.tail, "checkbox")
    val hideColumns = map.keyList.drop(6)
    hideColumns.foreach { x =>
      $(s"#${tableId}").bootstrapTable("hideColumn", x)
      $(s"input:checkbox[value='${x}']").attr("checked", false)
    }
  }

  def ajaxRequest: js.Function = (params: js.Dictionary[js.Any]) => {
    val url = g.jsRoutes.controllers.AnnoController.getAnnoByServer().url.toString
    val dataMap = params("data").toString.toJDS.toMap
    val queryMap = Tool.getQueryMap(parentId)
    val dataDict = (dataMap ++ queryMap ++ Map("allSearch" -> dataMap("search"))).toJSDictionary
    val data = JSON.stringify(dataDict)
    Ajax.post(url = s"${url}", data = s"${data}",
      headers = Map("Content-Type" -> "application/json"),
      responseType = "application/json").map { xhr =>
      val json = xhr.responseText.toJArJDJAn
      val successF = params("success").asInstanceOf[js.Function1[js.Any, js.Any]]
      successF(json)
    }
  }


}
